package org.jsola.hr.service.async.impl;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.jsola.admin.vo.AreaReduceVO;
import org.jsola.admin.vo.SiteVO;
import org.jsola.common.SafeKit;
import org.jsola.common.StrKit;
import org.jsola.hr.common.EmpFieldModuleCodeKit;
import org.jsola.hr.common.FormatUtils;
import org.jsola.hr.constant.EducationLevelEnum;
import org.jsola.hr.constant.PersonalEventEnum;
import org.jsola.hr.dto.*;
import org.jsola.hr.dto.excel.EmpImportSocRelatedDTO;
import org.jsola.hr.entity.*;
import org.jsola.hr.provider.IAdminProviderService;
import org.jsola.hr.query.CompanyNecessaryFieldQuery;
import org.jsola.hr.query.ModuleFieldQuery;
import org.jsola.hr.service.*;
import org.jsola.hr.service.async.IAsyncEmpInfoDetailService;
import org.jsola.hr.vo.*;
import org.jsola.user.core.TokenUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StopWatch;

import java.util.*;
import java.util.concurrent.Future;
import java.util.stream.Collectors;

import static org.jsola.hr.constant.HrConstants.JIA_FANG_QY;
import static org.jsola.hr.constant.HrConstants.JIA_FANG_SY;

/**
 * 花名册人员详情异步导入
 *
 * @author wcl
 */
@Slf4j
@Service("hrAsyncEmpInfoServiceImpl")
public class AsyncEmpInfoDetailServiceImpl implements IAsyncEmpInfoDetailService {

    @Autowired
    private IDepInfoService depInfoService;

    @Autowired
    private IPositionInfoService positionInfoService;

    @Autowired
    private IEmpEducationService empEducationService;

    @Autowired
    private ICompanyAdditionalFieldsService companyAdditionalFieldsService;

    @Autowired
    private IEmpDepService empDepService;

    @Autowired
    private IEmpPositionService empPositionService;

    @Autowired
    private IEmpAdditionalFieldsService empAdditionalFieldsService;

    @Autowired
    private IEmpPaperContractService empPaperContractService;

    @Autowired
    private IEmpContractService empContractService;

    @Autowired
    private IOperationEmpRecordService operationEmpRecordService;

    @Autowired
    private IEmpSocRelatedService empSocRelatedService;

    @Autowired
    private IAdminProviderService adminProviderService;

    @Autowired
    private IEmpCardService empCardService;

    @Autowired
    private IEmpFamilyService empFamilyService;

    @Autowired
    private IEmpRewardPunishService empRewardPunishService;

    @Autowired
    private IEmpCertificateService empCertificateService;

    @Autowired
    private IEmpContactsService empContactsService;

    @Autowired
    private IEmpTrainService empTrainService;

    @Autowired
    private IEmpWorkService empWorkService;

    @Autowired
    private ICompanyNecessaryFieldService companyNecessaryFieldService;

    @Autowired
    private IEmpInfoService empInfoService;

    @Autowired
    private IPersonalEventService personalEventService;

    /**
     * 自定义字段类型-地区
     */
    private static final Integer FIELD_TYPE_AREA = 6;

    @Async
    @Override
    public Future<String> saveDept(EmpInfoDO empInfo, String companyId, Map<String, String> depNameIdMap, TokenUser tokenUser) {

        try {
            // 部门 第一层是租户层 第二层是用工单位层 根据用工单位Id查询 name不传 结果唯一
            DepInfoDO companyDepInfoDO = depInfoService.selectByNameAndLevel(null, 2, null, companyId, tokenUser);
            // 实际部门Id
            String depId = null;
            if (companyDepInfoDO != null && StringUtils.isNotBlank(empInfo.getDepName())) {
                depId = depNameIdMap.get(empInfo.getDepName());
                if (depId == null) {
                    // 公司级部门
                    String parentId = companyDepInfoDO.getId();
                    String[] split = empInfo.getDepName().split("/");
                    for (int i = 0; i < split.length; i++) {
                        // 下级部门
                        DepInfoDO depInfoDO = depInfoService.selectByNameAndLevel(split[i], i + 3, parentId, companyId, tokenUser);
                        if (depInfoDO == null) {
                            DepInfoAddDTO depInfoAddDTO = new DepInfoAddDTO();
                            depInfoAddDTO.setName(split[i]);
                            depInfoAddDTO.setLevel(i + 3);
                            depInfoAddDTO.setParentId(parentId);
                            depInfoAddDTO.setAddress("");
                            depInfoAddDTO.setSort(1);
                            depInfoAddDTO.setCompanyId(companyId);
                            DepInfoVO save = depInfoService.save(depInfoAddDTO, tokenUser);
                            depInfoDO = save.to(DepInfoDO.class);
                        }
                        parentId = depInfoDO.getId();
                        // 最后一次的Id为最终Id
                        depId = parentId;
                        // 新建部门放入map(key为全路径 下次同名不需要重新查询 节约时间)
                        depNameIdMap.put(empInfo.getDepName(), depId);
                    }
                }
            }
            if (depId != null) {
                publishEmpDep(Collections.singletonList(depId), companyId, empInfo.getId(), tokenUser);
            }
        } catch (Exception e) {
            log.error("花名册导入异步保存部门失败：{}", e.getMessage());
            return new AsyncResult<>(e.getMessage());
        }

        return new AsyncResult<>("");
    }

    @Async
    @Override
    public Future<String> savePosition(EmpInfoDO empInfo, String companyId, TokenUser tokenUser) {
        try {

            //岗位
            PositionInfoDO positionInfoDO = positionInfoService
                    .selectByNameAndLevel(null, 1, null, companyId, tokenUser);
            // 部门名称(全路径)-部门Id
            Map<String, String> depNameIdMap = new HashMap<>();
            List<String> positionIdList = new ArrayList<>();
            if (positionInfoDO != null && StringUtils.isNotBlank(empInfo.getPositionName())) {
                // 分类名称
                String typeName;
                // 岗位名称
                String name;
                if (empInfo.getPositionName().contains("/")) {
                    // 含有分类
                    String[] split = empInfo.getPositionName().split("/");
                    typeName = split[0];
                    name = split[1];
                } else {
                    // 不含分类
                    typeName = "默认类型";
                    name = empInfo.getPositionName();
                }
                // 岗位类型
                String parentId = positionInfoDO.getId();
                PositionInfoDO typePositionInfoDO = positionInfoService
                        .selectByNameAndLevel(typeName, 2, parentId, companyId, tokenUser);
                if (typePositionInfoDO == null) {
                    PositionInfoAddDTO positionInfoAddDTO = new PositionInfoAddDTO();
                    positionInfoAddDTO.setCompanyId(companyId);
                    positionInfoAddDTO.setLevel(2);
                    positionInfoAddDTO.setName(typeName);
                    positionInfoAddDTO.setParentId(parentId);
                    positionInfoAddDTO.setSort(0);
                    positionInfoAddDTO.setType(2);
                    PositionInfoVO save = positionInfoService.save(positionInfoAddDTO, tokenUser);
                    typePositionInfoDO = save.to(PositionInfoDO.class);
                }
                // 岗位
                PositionInfoDO onePositionInfoDO = positionInfoService
                        .selectByNameAndLevel(name, 3, typePositionInfoDO.getId(), companyId, tokenUser);
                if (onePositionInfoDO == null) {
                    PositionInfoAddDTO positionInfoAddDTO = new PositionInfoAddDTO();
                    positionInfoAddDTO.setCompanyId(companyId);
                    positionInfoAddDTO.setLevel(3);
                    positionInfoAddDTO.setName(name);
                    positionInfoAddDTO.setParentId(typePositionInfoDO.getId());
                    positionInfoAddDTO.setSort(0);
                    positionInfoAddDTO.setType(1);
                    PositionInfoVO save = positionInfoService.save(positionInfoAddDTO, tokenUser);
                    onePositionInfoDO = save.to(PositionInfoDO.class);
                }
                positionIdList.add(onePositionInfoDO.getId());
            }
            if (!CollectionUtils.isEmpty(positionIdList)) {
                publishEmpPosition(positionIdList, companyId, empInfo.getId(), tokenUser);
            }
        } catch (Exception e) {
            log.error("花名册导入异步保存岗位失败：{}", e.getMessage());
            return new AsyncResult<>(e.getMessage());
        }
        return new AsyncResult<>("");
    }

    @Async
    @Override
    public Future<String> saveContract(EmpInfoDO empInfo, String companyId, TokenUser tokenUser) {
        try {
// 合同类型未填写 默认电子合同
            if (StringUtils.isBlank(empInfo.getEmpContractType()) && (null != empInfo.getContractStartDate()
                    || null != empInfo.getContractEndDate() || null != empInfo.getContractExpire()
                    || null != empInfo.getContractsRemark() || null != empInfo.getContractExpireStr())) {
                empInfo.setEmpContractType("电子合同");
            }
            if ("纸质合同".equals(empInfo.getEmpContractType())) {
                List<EmpPaperContractDTO> empPaperContractList = new ArrayList<>();
                EmpPaperContractDTO empPaperContractDTO = new EmpPaperContractDTO();
                empPaperContractDTO.setName(empInfo.getContractsName());
                empPaperContractDTO.setType(empInfo.getFileTypeValue());
                empPaperContractDTO.setStartTime(empInfo.getContractStartDate());
                empPaperContractDTO.setEndTime(empInfo.getContractEndDate());
                empPaperContractDTO.setTimeLimit(empInfo.getContractExpire());
                empPaperContractDTO.setRemarks(empInfo.getContractsRemark());
                empPaperContractDTO.setNumber(empInfo.getContractsNumber());
                empPaperContractDTO.setCompanyName(empInfo.getCompanyName());
                empPaperContractDTO.setSubscribeTime(empInfo.getSubscribeTime());
                empPaperContractDTO.setStatus(empInfo.getPaperContractsStatus());
                empPaperContractDTO.setCompanyId(companyId);
                if (StringUtils.isNotBlank(empInfo.getContractExpireStr())) {
                    try {
                        if (empInfo.getContractExpireStr().contains("年")) {
                            empPaperContractDTO.setTimeLimit(Integer
                                    .parseInt(empInfo.getContractExpireStr().replace("年", "")));
                            empPaperContractDTO.setTimeLimitType(1);
                        } else if (empInfo.getContractExpireStr().contains("月")) {
                            empPaperContractDTO.setTimeLimit(Integer
                                    .parseInt(empInfo.getContractExpireStr().replace("月", "")));
                            empPaperContractDTO.setTimeLimitType(2);
                        } else if (empInfo.getContractExpireStr().contains("日")) {
                            empPaperContractDTO.setTimeLimit(Integer
                                    .parseInt(empInfo.getContractExpireStr().replace("日", "")));
                            empPaperContractDTO.setTimeLimitType(3);
                        } else {
                            log.error("花名册批量导入员工：" + empInfo.getName() + "的纸质合同的合同期限有误："
                                    + empInfo.getContractExpireStr());
                        }
                    } catch (NumberFormatException e) {
                        log.error("花名册批量导入员工：" + empInfo.getName() + "的纸质合同的合同期限有误："
                                + empInfo.getContractExpireStr());
                    }
                }
                empPaperContractList.add(empPaperContractDTO);
                publishEmpPaperContractList(empPaperContractList, companyId, empInfo.getId(), tokenUser);
            } else if ("电子合同".equals(empInfo.getEmpContractType())) {
                List<EmpContractDTO> empContractList = new ArrayList<>();
                EmpContractDTO empContractDTO = new EmpContractDTO();
                empContractDTO.setName(empInfo.getContractsName());
                empContractDTO.setType(empInfo.getFileTypeValue());
                empContractDTO.setStartTime(empInfo.getContractStartDate());
                empContractDTO.setEndTime(empInfo.getContractEndDate());
                empContractDTO.setTermYear(empInfo.getContractExpire());
                empContractDTO.setRemark(empInfo.getContractsRemark());
                empContractDTO.setCompanyId(companyId);
                if (StringUtils.isNotBlank(empInfo.getContractExpireStr())) {
                    try {
                        if (empInfo.getContractExpireStr().contains("年")) {
                            empContractDTO.setTermYear(Integer
                                    .parseInt(empInfo.getContractExpireStr().replace("年", "")));
                        } else if (empInfo.getContractExpireStr().contains("月")) {
                            empContractDTO.setTermMonth(Integer
                                    .parseInt(empInfo.getContractExpireStr().replace("月", "")));
                        } else if (empInfo.getContractExpireStr().contains("日")) {
                            empContractDTO.setTermDay(Integer
                                    .parseInt(empInfo.getContractExpireStr().replace("日", "")));
                        } else {
                            log.error("花名册批量导入员工：" + empInfo.getName() + "的电子合同的合同期限有误："
                                    + empInfo.getContractExpireStr());
                        }
                    } catch (NumberFormatException e) {
                        log.error("花名册批量导入员工：" + empInfo.getName() + "的电子合同的合同期限有误："
                                + empInfo.getContractExpireStr());
                    }
                }
                empContractList.add(empContractDTO);
                publishEmpContractList(empContractList, companyId, empInfo.getId(), tokenUser);
            }
        } catch (Exception e) {
            log.error("花名册导入异步保存合同失败：{}", e.getMessage());
            return new AsyncResult<>(e.getMessage());
        }

        return new AsyncResult<>("");
    }

    @Override
    public Future<String> saveEducation(EmpInfoDO empInfo, String companyId, boolean isAdd, TokenUser tokenUser) {
        try {
            // 只有新增才会新建一条学历，修改不处理
            if (StrKit.isNotEmpty(empInfo.getEducation()) && isAdd) {
                EducationLevelEnum educationLevelEnum = EducationLevelEnum.findByDesc(empInfo.getEducation());
                if (educationLevelEnum != null) {
                    EmpEducationAddDTO empEducationAddDTO = new EmpEducationAddDTO();
                    empEducationAddDTO.setEmpId(empInfo.getId());
                    empEducationAddDTO.setCompanyId(companyId);
                    empEducationAddDTO.setEducation(educationLevelEnum.getValue());
                    empEducationService.save(empEducationAddDTO, tokenUser);
                }
            }
        } catch (Exception e) {
            log.error("花名册导入异步保存学历失败：{}", e.getMessage());
            return new AsyncResult<>(e.getMessage());
        }
        return new AsyncResult<>("");
    }

    @Async
    @Override
    public Future<String> saveAddition(EmpInfoDO empInfo, String companyId, List<AreaReduceVO> areaList, TokenUser tokenUser) {
        try {
            // 自定义字段
            if (empInfo.getFieldNameMap() != null) {
                List<EmpAdditionalFieldsAddDTO> empAdditionalFieldsAddDTOList = new ArrayList<>();
                // 导入自定义字段
                for (String filedName : empInfo.getFieldNameMap().keySet()) {
                    List<CompanyAdditionalFieldsDO> companyAdditionalFieldsDOList
                            = companyAdditionalFieldsService.selectByModuleAndFiledName(null, filedName, companyId);
                    // 匹配到公司的自定义字段
                    if (!CollectionUtils.isEmpty(companyAdditionalFieldsDOList)) {
                        CompanyAdditionalFieldsDO companyAdditionalFieldsDO = companyAdditionalFieldsDOList.get(0);
                        String content = empInfo.getFieldNameMap().get(filedName);
                        // 如果是地区类型，要转为code
                        if (Objects.equals(FIELD_TYPE_AREA, companyAdditionalFieldsDO.getFieldType())) {
                            String areaCode = FormatUtils.cityNameToAreaCode(content, areaList);
                            // 如果识别不了自定义地区字段，不进数据库
                            if (StrKit.isNotEmpty(areaCode)) {
                                content = areaCode;
                            } else {
                                continue;
                            }
                        }
                        EmpAdditionalFieldsAddDTO empAdditionalFieldsAddDTO = new EmpAdditionalFieldsAddDTO();
                        empAdditionalFieldsAddDTO.setCompanyId(companyId);
                        empAdditionalFieldsAddDTO.setEmpId(empInfo.getId());
                        empAdditionalFieldsAddDTO.setFieldId(companyAdditionalFieldsDO.getId());
                        empAdditionalFieldsAddDTO.setModuleCode(companyAdditionalFieldsDO.getModuleCode());
                        empAdditionalFieldsAddDTO.setContent(content);
                        empAdditionalFieldsAddDTOList.add(empAdditionalFieldsAddDTO);
                    }
                }
                // 自定义字段 按ModuleCode分组
                Map<String, List<EmpAdditionalFieldsAddDTO>> moduleCodeListMap = empAdditionalFieldsAddDTOList
                        .parallelStream().collect(Collectors.groupingBy(EmpAdditionalFieldsAddDTO::getModuleCode));
                for (String moduleCode : moduleCodeListMap.keySet()) {
                    empAdditionalFieldsService.savePreDelete(empInfo.getId(), companyId, moduleCode
                            , moduleCodeListMap.get(moduleCode), tokenUser);
                }
            }
        } catch (Exception e) {
            log.error("花名册导入异步保存自定义字段失败：{}", e.getMessage());
            return new AsyncResult<>(e.getMessage());
        }
        return new AsyncResult<>("");
    }

    @Async
    @Override
    public Future<String> saveOperationEmpRecord(EmpInfoDO empInfo, String companyId, List<AreaReduceVO> areaList, boolean isAdd, TokenUser tokenUser) {
        if (!isAdd) {
            return new AsyncResult<>("");
        }
        try {
            OperationEmpRecordAddDTO operationEmpRecordAddDTO = new OperationEmpRecordAddDTO();
            operationEmpRecordAddDTO.setEmpId(empInfo.getId());
            operationEmpRecordAddDTO.setEmpStatus(3);
            operationEmpRecordAddDTO.setQueryType(2);
            operationEmpRecordAddDTO.setInputUserId(tokenUser.getUserId());
            operationEmpRecordAddDTO.setUserId(empInfo.getUserId());
            operationEmpRecordAddDTO.setSourceType(1);
            operationEmpRecordAddDTO.setSourceTypeInfo("PC入职");
            operationEmpRecordAddDTO.setCompanyId(empInfo.getCompanyId());
            operationEmpRecordAddDTO.setMethodPath("org.jsola.hr.service.async.impl.AsyncEmpInfoDetailServiceImpl.saveOperationEmpRecord");
            operationEmpRecordService.save(operationEmpRecordAddDTO, tokenUser);
        } catch (Exception e) {
            log.error("花名册导入异步保存今日新增失败：{}", e.getMessage());
            return new AsyncResult<>(e.getMessage());
        }
        return new AsyncResult<>("");
    }

    /**
     * 员工部门
     *
     * @param depIdList 部门id集合
     * @param companyId 公司id
     * @param empId     员工id
     * @param tokenUser 当前用户
     */
    private void publishEmpDep(List<String> depIdList, String companyId, String empId, TokenUser tokenUser) {
        if (CollectionUtils.isEmpty(depIdList)) {
            return;
        }
        List<EmpDepAddDTO> empDepAddList = new ArrayList<>();
        List<DepInfoDO> depInfoDOList = depInfoService.selectByIds(depIdList, tokenUser);
        depInfoDOList.forEach(depInfoDO -> {
            EmpDepAddDTO empDepAddDTO = new EmpDepAddDTO();
            empDepAddDTO.setDepId(depInfoDO.getId());
            empDepAddDTO.setEmpId(empId);
            empDepAddDTO.setCompanyId(companyId);
            empDepAddList.add(empDepAddDTO);
        });
        if (!CollectionUtils.isEmpty(empDepAddList)) {
            empDepService.publishEmpDepList(empDepAddList, tokenUser);
        }
    }

    /**
     * 员工岗位
     *
     * @param positionIdList 岗位ID列表
     * @param companyId      公司id
     * @param empId          员工id
     * @param tokenUser      当前用户
     */
    private void publishEmpPosition(List<String> positionIdList, String companyId, String empId, TokenUser tokenUser) {
        if (CollectionUtils.isEmpty(positionIdList)) {
            return;
        }
        List<EmpPositionAddDTO> empPositionAddList = new ArrayList<>();
        positionIdList.forEach(
                positionId -> {
                    PositionInfoVO positionInfo = positionInfoService.selectById(positionId, tokenUser.getSiteId());
                    if (!Objects.isNull(positionInfo)) {
                        EmpPositionAddDTO empPositionAddDTO = new EmpPositionAddDTO();
                        empPositionAddDTO.setPositionId(positionId);
                        empPositionAddDTO.setEmpId(empId);
                        empPositionAddDTO.setCompanyId(companyId);
                        empPositionAddList.add(empPositionAddDTO);
                    }
                }
        );
        if (!CollectionUtils.isEmpty(empPositionAddList)) {
            empPositionService.publishEmpPositionList(empPositionAddList, tokenUser);
        }
    }

    /**
     * 纸质合同
     *
     * @param empPaperContractList 纸质合同
     * @param tokenUser            当前用户
     */
    private void publishEmpPaperContractList(List<EmpPaperContractDTO> empPaperContractList, String companyId, String empId, TokenUser tokenUser) {
        if (empPaperContractList == null) {
            return;
        }
        // 发布
        empPaperContractService.publishEmpPaperContractList(empPaperContractList, companyId, empId, tokenUser);
    }

    /**
     * 员工合同
     *
     * @param empContractList 员工合同
     * @param tokenUser       当前用户
     */
    private void publishEmpContractList(List<EmpContractDTO> empContractList, String companyId, String empId, TokenUser tokenUser) {
        if (empContractList == null) {
            return;
        }
        // 发布
        empContractService.publishEmpContractList(empContractList, companyId, empId, tokenUser);
    }

    @Override
    @Async
    public Future<EmpAllInfoVO> listDepNameByEmp(String companyId, String empId, String siteId) {
        //部门集合
        List<EmpDepDO> empDepList = empDepService.listAllByEmpId(companyId, empId, siteId);
        //
        Map<String, String> empDepMap = new HashMap<>();
        if (!CollectionUtils.isEmpty(empDepList)) {
            // 部门id与部门名称的接口
            Map<String, String> depMap = depInfoService.getDepIdAndNameMapByCompany(companyId, siteId);
            // 人员所属部门名称
            empDepList.parallelStream()
                    .filter(empDep -> depMap.containsKey(empDep.getDepId()))
                    .forEach(empDep ->
                            empDepMap.put(empDep.getDepId(), depMap.get(empDep.getDepId()))
                    );
        }

        //部门集合
        if (empDepMap.size() > 0) {
            EmpAllInfoVO empAllInfoVO = new EmpAllInfoVO();
            List<String> depIdList = new ArrayList<>();
            List<String> depNameList = new ArrayList<>();
            empDepMap.forEach(
                    (key, value) -> {
                        depIdList.add(key);
                        depNameList.add(value);
                    }
            );
            empAllInfoVO.setDepIdList(depIdList);
            empAllInfoVO.setDepName(String.join(",", depNameList));
            return new AsyncResult<EmpAllInfoVO>(empAllInfoVO);
        }
        return new AsyncResult<EmpAllInfoVO>(null);

    }

    @Override
    @Async
    public Future<EmpAllInfoVO> listPositionNameByEmp(String companyId, String empId, String siteId) {
        //岗位集合
        List<EmpPositionDO> empPositionList = empPositionService.listAllByEmpId(companyId, empId, siteId);
        //
        Map<String, String> empPositionMap = new HashMap<>();
        if (!CollectionUtils.isEmpty(empPositionList)) {
            // 岗位id与岗位名称的接口
            Map<String, String> positionMap = positionInfoService.getPositionIdAndNameMapByCompany(companyId, siteId);
            // 人员所属岗位名称
            empPositionList.stream()
                    .filter(empPosition -> positionMap.containsKey(empPosition.getPositionId()))
                    .forEach(empPosition ->
                            empPositionMap.put(empPosition.getPositionId(), positionMap.get(empPosition.getPositionId()))
                    );

        }

        if (empPositionMap.size() > 0) {
            EmpAllInfoVO empAllInfoVO = new EmpAllInfoVO();
            List<String> positionIdList = new ArrayList<>();
            List<String> positionNameList = new ArrayList<>();
            empPositionMap.forEach(
                    (key, value) -> {
                        positionIdList.add(key);
                        positionNameList.add(value);
                    }
            );
            empAllInfoVO.setPositionIdList(positionIdList);
            empAllInfoVO.setPositionName(String.join(",", positionNameList));
            return new AsyncResult<EmpAllInfoVO>(empAllInfoVO);
        }
        return new AsyncResult<EmpAllInfoVO>(null);
    }

    @Override
    @Async
    public Future<EmpAllInfoVO> cardListByEmpId(String empInfoId, String siteId) {
        List<EmpCardDO> empCardList = empCardService.listByEmpId(empInfoId, siteId);
        if (!CollectionUtils.isEmpty(empCardList)) {
            EmpAllInfoVO empAllInfoVO = new EmpAllInfoVO();
            List<EmpCardVO> empCardVoList = empCardList.stream().map(empCard -> empCard.to(EmpCardVO.class))
                    .collect(Collectors.toList());
            empAllInfoVO.setEmpCardList(empCardVoList);
            return new AsyncResult<EmpAllInfoVO>(empAllInfoVO);
        }
        return new AsyncResult<EmpAllInfoVO>(null);
    }

    @Override
    @Async
    public Future<EmpAllInfoVO> familyListByEmpId(String empInfoId, String siteId) {
        List<EmpFamilyDO> empFamilyList = empFamilyService.listByEmpId(empInfoId, siteId);
        if (!CollectionUtils.isEmpty(empFamilyList)) {
            EmpAllInfoVO empAllInfoVO = new EmpAllInfoVO();
            List<EmpFamilyVO> empFamilyVoList = empFamilyList.stream().map(empFamilyDO -> empFamilyDO.to(EmpFamilyVO.class))
                    .collect(Collectors.toList());
            empAllInfoVO.setEmpFamilyList(empFamilyVoList);
            return new AsyncResult<EmpAllInfoVO>(empAllInfoVO);
        }
        return new AsyncResult<EmpAllInfoVO>(null);
    }

    @Override
    @Async
    public Future<EmpAllInfoVO> rewardPunishListByEmpId(String empInfoId, String siteId) {
        List<EmpRewardPunishDO> empRewardPunishList = empRewardPunishService.listByEmpId(empInfoId, siteId);
        if (!CollectionUtils.isEmpty(empRewardPunishList)) {
            EmpAllInfoVO empAllInfoVO = new EmpAllInfoVO();
            List<EmpRewardPunishVO> empRewardPunishVoList = empRewardPunishList.stream().map(empRewardPunishDO -> empRewardPunishDO.to(EmpRewardPunishVO.class))
                    .collect(Collectors.toList());
            empAllInfoVO.setEmpRewardPunishList(empRewardPunishVoList);
            return new AsyncResult<EmpAllInfoVO>(empAllInfoVO);
        }
        return new AsyncResult<EmpAllInfoVO>(null);
    }

    @Override
    @Async
    public Future<EmpAllInfoVO> certificateListByEmpId(String empInfoId, String siteId) {
        List<EmpCertificateDO> empCertificateList = empCertificateService.listByEmpId(empInfoId, siteId);
        if (!CollectionUtils.isEmpty(empCertificateList)) {
            EmpAllInfoVO empAllInfoVO = new EmpAllInfoVO();
            List<EmpCertificateVO> empCertificateVoList = empCertificateList.stream().map(empCertificate -> empCertificate.to(EmpCertificateVO.class))
                    .collect(Collectors.toList());
            empAllInfoVO.setEmpCertificateList(empCertificateVoList);
            return new AsyncResult<EmpAllInfoVO>(empAllInfoVO);
        }
        return new AsyncResult<EmpAllInfoVO>(null);
    }

    @Override
    @Async
    public Future<EmpAllInfoVO> contractListByEmpId(String empInfoId, String siteId) {
        List<EmpContractDO> empContractList = empContractService.listByEmpId(empInfoId, siteId);
        if (!CollectionUtils.isEmpty(empContractList)) {
            EmpAllInfoVO empAllInfoVO = new EmpAllInfoVO();
            List<EmpContractVO> empContractVoList = empContractList.stream().map(empContract -> empContract.to(EmpContractVO.class))
                    .collect(Collectors.toList());
            empAllInfoVO.setEmpContractList(empContractVoList);
            return new AsyncResult<EmpAllInfoVO>(empAllInfoVO);
        }
        return new AsyncResult<EmpAllInfoVO>(null);
    }

    @Override
    @Async
    public Future<EmpAllInfoVO> contactListByEmpId(String empInfoId, String siteId) {
        List<EmpContactsDO> empContactsList = empContactsService.listByEmpId(empInfoId, siteId);
        if (!CollectionUtils.isEmpty(empContactsList)) {
            EmpAllInfoVO empAllInfoVO = new EmpAllInfoVO();
            List<EmpContactsVO> empContactsVoList = empContactsList.stream().map(empContacts -> empContacts.to(EmpContactsVO.class))
                    .collect(Collectors.toList());
            empAllInfoVO.setEmpContactsList(empContactsVoList);
            return new AsyncResult<EmpAllInfoVO>(empAllInfoVO);
        }
        return new AsyncResult<EmpAllInfoVO>(null);
    }

    @Override
    @Async
    public Future<EmpAllInfoVO> educationListByEmpId(String empInfoId, String siteId) {
        List<EmpEducationDO> empEducationList = empEducationService.listByEmpId(empInfoId, siteId);
        if (!CollectionUtils.isEmpty(empEducationList)) {
            EmpAllInfoVO empAllInfoVO = new EmpAllInfoVO();
            List<EmpEducationVO> empEducationVoList = empEducationList.stream().map(empEducation -> empEducation.to(EmpEducationVO.class))
                    .collect(Collectors.toList());
            empAllInfoVO.setEmpEducationList(empEducationVoList);
            return new AsyncResult<EmpAllInfoVO>(empAllInfoVO);
        }
        return new AsyncResult<EmpAllInfoVO>(null);
    }

    @Override
    @Async
    public Future<EmpAllInfoVO> trainListByEmpId(String empInfoId, String siteId) {
        List<EmpTrainDO> empTrainList = empTrainService.listByEmpId(empInfoId, siteId);
        if (!CollectionUtils.isEmpty(empTrainList)) {
            EmpAllInfoVO empAllInfoVO = new EmpAllInfoVO();
            List<EmpTrainVO> empTrainVoList = empTrainList.stream().map(empTrain -> empTrain.to(EmpTrainVO.class))
                    .collect(Collectors.toList());
            empAllInfoVO.setEmpTrainList(empTrainVoList);
            return new AsyncResult<EmpAllInfoVO>(empAllInfoVO);
        }
        return new AsyncResult<EmpAllInfoVO>(null);
    }

    @Override
    @Async
    public Future<EmpAllInfoVO> empWorkListByEmpId(String empInfoId, String siteId) {
        List<EmpWorkDO> empWorkList = empWorkService.listByEmpId(empInfoId, siteId);
        if (!CollectionUtils.isEmpty(empWorkList)) {
            EmpAllInfoVO empAllInfoVO = new EmpAllInfoVO();
            List<EmpWorkVO> empWorkVoList = empWorkList.stream().map(empWork -> empWork.to(EmpWorkVO.class))
                    .collect(Collectors.toList());
            empAllInfoVO.setEmpWorkList(empWorkVoList);
            return new AsyncResult<EmpAllInfoVO>(empAllInfoVO);
        }
        return new AsyncResult<EmpAllInfoVO>(null);
    }

    @Override
    @Async
    public Future<EmpAllInfoVO> paperContractListByEmpId(String empInfoId, String siteId) {
        List<EmpPaperContractDO> empPaperContractList = empPaperContractService.listContractByEmpId(empInfoId, siteId);
        if (!CollectionUtils.isEmpty(empPaperContractList)) {
            EmpAllInfoVO empAllInfoVO = new EmpAllInfoVO();
            List<EmpPaperContractVO> empPaperContractVoList = empPaperContractList.stream().map(contract -> contract.to(EmpPaperContractVO.class))
                    .collect(Collectors.toList());
            empAllInfoVO.setEmpPaperContractList(empPaperContractVoList);
            return new AsyncResult<EmpAllInfoVO>(empAllInfoVO);
        }
        return new AsyncResult<EmpAllInfoVO>(null);
    }

    @Override
    @Async
    public Future<EmpAllInfoVO> additionListByEmpId(EmpInfoDO empInfoDO) {
        CompanyNecessaryFieldQuery companyNecessaryFieldQuery = new CompanyNecessaryFieldQuery();
        companyNecessaryFieldQuery.setCompanyId(empInfoDO.getCompanyId());
        companyNecessaryFieldQuery.setEmpInfoId(empInfoDO.getId());
        TokenUser tokenUser = new TokenUser();
        tokenUser.setUserId(empInfoDO.getCreateUserId());
        tokenUser.setSiteId(empInfoDO.getSiteId());
        CompanyFieldAndValueListVO companyFieldAndValueListVO =
                companyNecessaryFieldService.listAllForApp(companyNecessaryFieldQuery, tokenUser);
        if (companyFieldAndValueListVO != null) {
            EmpAllInfoVO empAllInfoVO = new EmpAllInfoVO();
            empAllInfoVO.setCompanyAdditionalFieldsListBasicVOList(
                    companyFieldAndValueListVO.getCompanyAdditionalFieldsBasicVOList());
            //额外联系信息
            empAllInfoVO.setCompanyAdditionalFieldsListContactVOList(
                    companyFieldAndValueListVO.getCompanyAdditionalFieldsContactVOList());
            //额外附件信息
            empAllInfoVO.setCompanyAdditionalFieldsListAttachmentVOList(
                    companyFieldAndValueListVO.getCompanyAdditionalFieldsAttachmentVOList());
            //员工档案资料
            empAllInfoVO.setCompanyAdditionalFieldsListArchiveVOList(
                    companyFieldAndValueListVO.getCompanyAdditionalFieldsArchiveVOList());
            //员工离职资料
            empAllInfoVO.setCompanyAdditionalFieldsListLeaveOfficeVOList(
                    companyFieldAndValueListVO.getCompanyAdditionalFieldsLeaveOfficeVOList());
            return new AsyncResult<EmpAllInfoVO>(empAllInfoVO);
        }
        return new AsyncResult<EmpAllInfoVO>(null);

    }

    @Override
    @Async
    public Future<Map<String, EmpFieldValueVO>> getEmpFieldValue(ModuleFieldQuery moduleFieldQuery, TokenUser tokenUser) {
        SiteVO site = adminProviderService.selectSiteById(tokenUser.getSiteId(), tokenUser);
        EmpFieldValueVO empFieldValueVO = new EmpFieldValueVO();
        String moduleCode = moduleFieldQuery.getModuleCode();
        String companyId = moduleFieldQuery.getCompanyId();

        StopWatch sw = new StopWatch("getEmpFieldValue moduleCode:");
        sw.start(moduleCode);
        //模块下的所有字段
        List<CompanyNecessaryFieldDO> companyNecessaryFieldList = companyNecessaryFieldService.selectByModuleCode(moduleCode, companyId, tokenUser.getSiteId());
        List<CompanyNecessaryFieldVO> fieldList = companyNecessaryFieldList.stream()
                .map(companyNecessaryFieldDO -> companyNecessaryFieldDO.to(CompanyNecessaryFieldVO.class))
                .collect(Collectors.toList());
        //查询所有自定义字段
        List<CompanyAdditionalFieldsListVO> companyAdditionalFieldsListVOList =
                companyAdditionalFieldsService.selectOpenByCompanyId(moduleFieldQuery.getCompanyId(), tokenUser.getSiteId());
        //所有自定义字段根据moduleCode分组
        Map<String, List<CompanyAdditionalFieldsListVO>> additionalFieldMap = companyAdditionalFieldsListVOList.stream()
                .collect(Collectors.groupingBy(CompanyAdditionalFieldsListVO::getModuleCode));
        //员工填的值map
        List<EmpAdditionalFieldsDO> empValueList = empAdditionalFieldsService.selectByCompanyId(moduleFieldQuery.getEmpInfoId(),
                companyId, moduleCode, tokenUser.getSiteId());
        Map<Long, String> empValueMap = empValueList.parallelStream().filter(empAdditionalFieldsDO -> empAdditionalFieldsDO.getContent() != null)
                .collect(Collectors.toMap(EmpAdditionalFieldsDO::getFieldId, EmpAdditionalFieldsDO::getContent));
        String empId = moduleFieldQuery.getEmpInfoId();
        //获取员工信息
        EmpInfoVO empInfoVO = empInfoService.selectById(empId, tokenUser.getSiteId());
        empFieldValueVO.setModuleCode(moduleCode);
        empFieldValueVO.setMultiple(EmpFieldModuleCodeKit.getModuleCodeSupportNecessary(moduleCode));
        if (empFieldValueVO.getMultiple()) {
            //多条字段的值设置需要通过不同的员工信息表
            switch (moduleCode) {
                case "empContacts":
                    //获取员工紧急联系人
                    List<EmpContactsDO> empContactsList = empContactsService.listByEmpId(empId, tokenUser.getSiteId());
                    empFieldValueVO.setListData(EmpFieldModuleCodeKit.processContactFieldList(fieldList, empContactsList));
                    break;
                case "empEducation":
                    //获取员工教育经历
                    List<EmpEducationDO> empEducationList = empEducationService.listByEmpId(empId, tokenUser.getSiteId());
                    empFieldValueVO.setListData(EmpFieldModuleCodeKit.processEducationFieldList(fieldList, empEducationList));
                    break;
                case "empFamily":
                    //获取员工家庭信息
                    List<EmpFamilyDO> empFamilyList = empFamilyService.listByEmpId(empId, tokenUser.getSiteId());
                    empFieldValueVO.setListData(EmpFieldModuleCodeKit.processFamilyFieldList(fieldList, empFamilyList));
                    break;
                case "empTrain":
                    //获取员工培训经历
                    List<EmpTrainDO> empTrainList = empTrainService.listByEmpId(empId, tokenUser.getSiteId());
                    empFieldValueVO.setListData(EmpFieldModuleCodeKit.processTrainFieldList(fieldList, empTrainList));
                    break;
                case "empWork":
                    //获取员工工作经历
                    List<EmpWorkDO> empWorkList = empWorkService.listByEmpId(empId, tokenUser.getSiteId());
                    empFieldValueVO.setListData(EmpFieldModuleCodeKit.processWorkFieldList(fieldList, empWorkList));
                    break;
                case "rewardsPunishments":
                    //获取员工的奖惩记录
                    List<EmpRewardPunishDO> empRewardPunish = empRewardPunishService.listByEmpId(empId, tokenUser.getSiteId());
                    empFieldValueVO.setListData(EmpFieldModuleCodeKit.processRewardPunishList(fieldList, empRewardPunish));
                    break;
                default:
                    break;
            }
        } else {
            //其他字段的值全从员工表中取
            Map<String, String> dataMap = EmpFieldModuleCodeKit.processEmpFieldList(fieldList, empInfoVO);
            if (JIA_FANG_QY.equals(site.getSiteType()) || JIA_FANG_SY.equals(site.getSiteType())) {
                dataMap.remove("postType");
            }
            //组装自定义字段的值
            List<CompanyAdditionalFieldsListVO> additionalFieldList = additionalFieldMap.get(moduleCode);
            if (additionalFieldList != null) {
                additionalFieldList.forEach(companyAdditionalFieldsListVO ->
                        dataMap.put(SafeKit.getString(companyAdditionalFieldsListVO.getId())
                                , SafeKit.getString(empValueMap.get(companyAdditionalFieldsListVO.getId()))));
            }
            if (dataMap.size() != 0) {
                empFieldValueVO.setData(dataMap);
                try {
                    if ("socAndPf".equals(moduleFieldQuery.getModuleCode())) {
                        EmpImportSocRelatedDTO empSocRelated = empSocRelatedService.findEmpSocRelated(moduleFieldQuery.getEmpInfoId(), moduleFieldQuery.getCompanyId(), tokenUser);
                        if (empSocRelated != null) {
                            dataMap.put("startPaymentDate", org.springframework.util.StringUtils
                                    .isEmpty(empSocRelated.getStartPaymentDate()) ? null : empSocRelated.getStartPaymentDate());
                            dataMap.put("insuredCity", org.springframework.util.StringUtils
                                    .isEmpty(empSocRelated.getInsuredCity()) ? null : empSocRelated.getInsuredCity());
                            dataMap.put("socAccount",org.springframework.util.StringUtils
                                    .isEmpty(empSocRelated.getSocAccount()) ? null : empSocRelated.getSocAccount());
                            dataMap.put("meAccount",org.springframework.util.StringUtils
                                    .isEmpty(empSocRelated.getMeAccount()) ? null : empSocRelated.getMeAccount());
                            dataMap.put("pfAccount",org.springframework.util.StringUtils
                                    .isEmpty(empSocRelated.getPfAccount()) ? null : empSocRelated.getPfAccount());
                        }
                    }
                } catch (Exception e) {
                    log.error("获取起缴时间或参保城市出错");
                }
            }
        }
        // 是否用POST请求
        boolean isPost = true;
        if (empFieldValueVO.getMultiple()) {
            if (!CollectionUtils.isEmpty(empFieldValueVO.getListData())) {
                isPost = false;
            }
        } else {
            if (Objects.nonNull(empFieldValueVO.getData())) {
                for (Map.Entry<String, String> entry : empFieldValueVO.getData().entrySet()) {
                    // 只要有一个数据不为空,就用PUT方法
                    if (Objects.nonNull(entry.getValue())) {
                        isPost = false;
                        break;
                    }
                }
            }
        }
        empFieldValueVO.setIsPost(isPost);

        Map<String, EmpFieldValueVO> map = new HashMap<>();
        map.put(moduleCode, empFieldValueVO);
        sw.stop();
        log.info("moduleCode :{} 耗时：{}",moduleCode, sw.getTotalTimeMillis());
        return new AsyncResult<Map<String, EmpFieldValueVO>>(map);
    }

    @Async
    @Override
    public void empCompleteInfoAsync(List<String> empIdList, TokenUser tokenUser) {
        EmpInfoDO tempEmpInfoDO = empInfoService.selectById(empIdList.get(0));
        log.info("异步检查员工必填字段是否已完善开始");
        Map<String, String> empIdNotCompleteMap = empInfoService.listNotComplete(tempEmpInfoDO.getCompanyId(), empIdList, tokenUser);
        for (String empId : empIdList) {
            EmpInfoDO empInfoDO = empInfoService.selectById(empId);
            String needComplete = empIdNotCompleteMap.get(empId);
            Boolean isImprove = empInfoDO.getIsImprove();
            log.info("异步检查员工必填字段是否已完善" + empInfoDO.getPhone() + " 必填字段： " + needComplete);
            if (StringUtils.isBlank(needComplete)) {
                // 如果必填字段为空,说明这人把该填的都填了
                // 并且这个人的必填状态是false,这个时候需要在用工档案添加一条此员工已完善信息的记录
                if (!isImprove) {
                    PersonalEventDO personalEventDO = new PersonalEventDO();
                    // 是否自动生成
                    personalEventDO.setIfAuto(true);
                    // 事件时间
                    personalEventDO.setEventTime(new Date());
                    // 事件类型(个人信息已完善)
                    personalEventDO.setEventType(PersonalEventEnum.DETAILS_INFO.getValue());
                    // 备注
                    personalEventDO.setDescription("个人信息已完善");
                    // 事件名称
                    personalEventDO.setEventName(PersonalEventEnum.DETAILS_INFO.getDesc());
                    personalEventDO.setUserId(empInfoDO.getUserId());
                    personalEventDO.setCompanyId(empInfoDO.getCompanyId());
                    personalEventDO.setEmpId(empInfoDO.getId());
                    personalEventService.save(personalEventDO, tokenUser.getSiteId(), tokenUser.getUserId());

                    EmpInfoDO param = new EmpInfoDO();
                    param.setId(empInfoDO.getId());
                    param.setIsImprove(true);
                    empInfoService.updateByIdSelective(param, empInfoDO.getSiteId(), tokenUser.getUserId());
                }
            } else {
                EmpInfoDO param = new EmpInfoDO();
                param.setId(empInfoDO.getId());
                param.setIsImprove(false);
                empInfoService.updateByIdSelective(param, empInfoDO.getSiteId(), tokenUser.getUserId());
            }
        }
        log.info("异步检查员工必填字段是否已完善完成");
    }

    @Async
    @Override
    public Future<String> saveEmpFamily(EmpInfoDO empInfo, String companyId, TokenUser tokenUser) {
        if (StringUtils.isBlank(empInfo.getFamilyName())
                && StringUtils.isBlank(empInfo.getFamilyPhone())
                && StringUtils.isBlank(empInfo.getFamilyWorkUnit())
                && StringUtils.isBlank(empInfo.getFamilyRelation())) {
            return new AsyncResult<>("");
        }
        try {
            EmpFamilyAddDTO empFamilyAddDTO = new EmpFamilyAddDTO();
            empFamilyAddDTO.setEmpId(empInfo.getId());
            empFamilyAddDTO.setCompanyId(companyId);
            empFamilyAddDTO.setName(empInfo.getFamilyName());
            empFamilyAddDTO.setPhone(empInfo.getFamilyPhone());
            empFamilyAddDTO.setWorkUnit(empInfo.getFamilyWorkUnit());
            empFamilyAddDTO.setRelation(empInfo.getFamilyRelation());
            empFamilyService.save(empFamilyAddDTO, tokenUser);
        } catch (Exception e) {
            log.error("花名册导入异步保存家庭成员失败：{}", e.getMessage());
            return new AsyncResult<>(e.getMessage());
        }
        return new AsyncResult<>("");
    }

    @Async
    @Override
    public Future<String> empContacts(EmpInfoDO empInfo, String companyId, TokenUser tokenUser) {
        if (StringUtils.isBlank(empInfo.getContactName())
                && StringUtils.isBlank(empInfo.getContactAddress())
                && StringUtils.isBlank(empInfo.getContactPhone())
                && StringUtils.isBlank(empInfo.getContactRelation())) {
            return new AsyncResult<>("");
        }

        try {
            EmpContactsAddDTO empContactsAddDTO = new EmpContactsAddDTO();
            empContactsAddDTO.setEmpId(empInfo.getId());
            empContactsAddDTO.setCompanyId(companyId);
            empContactsAddDTO.setName(empInfo.getContactName());
            empContactsAddDTO.setAddress(empInfo.getContactAddress());
            empContactsAddDTO.setPhone(empInfo.getContactPhone());
            empContactsAddDTO.setRelation(empInfo.getContactRelation());
            empContactsService.save(empContactsAddDTO, tokenUser);
        } catch (Exception e) {
            log.error("花名册导入异步保存家庭成员失败：{}", e.getMessage());
            return new AsyncResult<>(e.getMessage());
        }
        return new AsyncResult<>("");
    }
}
